package cc.realxyq.demo.lifecyle;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.lang.Nullable;

import java.lang.reflect.Constructor;
import java.util.concurrent.atomic.LongAdder;

/**
 *  这部分就是 各种类型 BeanPostProcessor 接口，在Bean 的生命周期中的 的介入时机，spring就是利用的BeanPostProcessor 的机制
 *  来介入 Bean的 生命周期的各个阶段的，
 *  阅读源码的心得，在spring中，通常是这样：
 *  1. 如果要介入所用Bean的生命周期使用BeanPostProcessor
 *  2. 如果是要对单个组件 进行增强，通常是结合 InitializingBean 接口来实现
 *
 * @author kwhan
 */
@EnableAspectJAutoProxy
@Slf4j
@Configuration
@Import({SpringLifeCycle.FullyBeanPostProcessor.class})
public class SpringLifeCycle {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringLifeCycle.class);
        context.registerBeanDefinition("demo",new RootBeanDefinition(DemoBean.class));
        // 这种方式注册 切面类，无效
        //context.registerBeanDefinition("aspect",new RootBeanDefinition(DemoAspect.class));
        DemoBean demo = context.getBean("demo", DemoBean.class);
        demo.divide(10,2);
        context.start();
        context.close();
    }

    //@Bean
    public DemoBean demo(){
        return new DemoBean();
    }

    /**
     * 这种方式 注册 切面类 有效
     * @return 切面类
     */
    @Bean
    public DemoAspect aspect(){
        return  new DemoAspect();
    }


    @Aspect
    public static class DemoAspect{

        @Pointcut(value = "execution(* cc.realxyq.demo.lifecyle.SpringLifeCycle.DemoBean.divide(..))")
        public void pointcut(){}

        @Before("pointcut()")
        public void demoBefore(){
            System.out.println("Before....................................");
        }
    }

    public static class DemoBean {
        DemoBean self;

        /**
         *  为了偷懒不想写2个bean循环引用了，
         *  通过这种方式刻意制造 循环引用，致使 SmartInstantiationAwareBeanPostProcessor 提前暴露对象
         * @param self 自身引用 自身
         */
        @SuppressWarnings("all")
        @Autowired
        public void setDemoBean2(DemoBean self) {
            this.self = self;
        }

        public int divide(int x, int y){
            return x/y;
        }
    }


    @Order
    public static class FullyBeanPostProcessor implements BeanPostProcessor, InstantiationAwareBeanPostProcessor,
            SmartInstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor,
            DestructionAwareBeanPostProcessor {



        private static final LongAdder LONG_ADDER = new LongAdder();

        /**
         *  调用构造方法之前 ，也可以说实例化之前（java层面，不是jvm层面）
         * @param beanClass 字节码类型
         * @param beanName 名称
         * @return 默认返回null 继续剩下的生命周期; 返回not null，这直接将这个对象，用bean 注册到容器中
         *
         * @throws BeansException 异常
         */
        @Nullable
        @Override
        public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.error("{}>>>>InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation", LONG_ADDER);
            }
            // 如果这里返回的 not null,则直接短路 跳过初始化 下一步直接跳转到 BeanPostProcessor.postProcessAfterInitialization
            // return "not null";
            // 返回null才会继续各个生命周期
            return null;
        }

        /**
         * 候选的构造函数，默认返回null，如果设置了特定的构造函数，将使用设置的
         *
         * 如果开启了AOP代理的话，AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor，中复写了 这个方法，
         * 返回为null，就是如果demo对象 开启了aop代理的话，就不走咱们自定义的这个
         * @param beanClass 要实例化的Class
         * @param beanName 名称
         * @return 返回要使用的构造函数
         * @throws BeansException 异常
         */
        @Nullable
        @Override
        public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName) throws BeansException {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.warn("{}>>>>SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors", LONG_ADDER);
            }
            return null;
        }

        /**
         * 各种缓存中的BeanDefinitions 对指定bean的给定合并bean定义进行后期处理。
         * 还是属于对BeanDefinition的 增强阶段
         * @param beanDefinition 定义信息，bean的蓝图
         * @param beanType 类型
         * @param beanName 名称
         */
        @Override
        public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.debug("{}>>>>MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition", LONG_ADDER);
            }
        }

        /**
         * 如果允许属性填充 ，则返回true，不允许属性设置的话，设置成false，则跳过属性赋值阶段
         * @param bean 对象
         * @param beanName 名称
         * @return 是否允许 填充属性
         * @throws BeansException 异常
         */
        @Override
        public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.error("{}>>>>InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation", LONG_ADDER);
            }
            return true;
        }

        /**
         *  循环引用的时候 提前暴露引用
         * @param bean 对象
         * @param beanName bean名称
         * @return 返回代理
         * @throws BeansException 异常
         */
        @Override
        public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.warn("{}>>>>SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference", LONG_ADDER);
            }
            return SmartInstantiationAwareBeanPostProcessor.super.getEarlyBeanReference(bean, beanName);
        }

        @Nullable
        @Override
        public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.error("{}>>>>InstantiationAwareBeanPostProcessor.postProcessProperties", LONG_ADDER);
            }
            return null;
        }

        @Nullable
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.info("{}>>>>BeanPostProcessor.postProcessBeforeInitialization", LONG_ADDER);
            }
            return null;
        }

        @Nullable
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.info("{}>>>>BeanPostProcessor.postProcessAfterInitialization", LONG_ADDER);
            }
            return null;
        }

        @Override
        public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
            if ("demo".equals(beanName)) {
                LONG_ADDER.increment();
                log.info("{}>>>>DestructionAwareBeanPostProcessor.postProcessBeforeDestruction", LONG_ADDER);
            }
        }

    }
}
